import io
import re
import subprocess
import tempfile
import threading
import time
import os
import uuid
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from openpyxl import load_workbook
import redis
from doc_service.models import RepModel, Report
from doc_service.utils import fake_sign, num_to_rmb
from reportservice.helpers import ApiResponse, create_directories_if_not_exist
import json
from datetime import datetime, timezone, timedelta
from oss_service.views import bucket,digital_bucket
from yida_app_service.chengxiang.task import convert_to_pdf, generateReportPdf
from yida_app_service.chengxiang.test import record_log, start_backup_task_test
from yida_app_service.chengxiang.xm_cloud_config import XmCloudClient
from yida_app_service.chengxiang.xm_digital_sign_config import XmDigitalSignClient
from yida_app_service.chengxiang_2025.views import encrypt_report
from yida_app_service.models import DocxRenderRecord
from yida_app_service.utils.common_utils import date_format
from .yida_config import YidaClient
import logging
import pandas as pd
import openpyxl
from openpyxl.styles import Border, Side
from openpyxl.utils.cell import range_boundaries
from openpyxl.utils import coordinate_to_tuple
import re
from concurrent.futures import ThreadPoolExecutor, as_completed
from queue import Queue
from threading import Thread
import requests
import fitz
from fitz import FileDataError
xm_digital_sign_client = XmDigitalSignClient()
yida_client = YidaClient()
xm_client = XmCloudClient()
redis_client = redis.StrictRedis(host='10.8.0.83', port=6379, db=5)
logger = logging.getLogger(__name__)
admin_user_id = "301546025724261514"
report_form_uuid = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"
finicial_form_uuid = "FORM-BAFAA96000BA4C44A0C8F3256EB00407RP4T"
report_type_form_uuid = "FORM-7F0A10A94E3D469882B2B1AA9700C1255JRO"
tmp_path = os.path.join(settings.BASE_DIR, r'yida_app_service/chengxiang/resorce')
# yida_app_service/chengxiang/resorce
thin_border = Border(left=Side(style='thin'), 
                     right=Side(style='thin'), 
                     top=Side(style='thin'), 
                     bottom=Side(style='thin'))
count = 0

REPORT_FORM_UUID = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"

# 打印所有的财务清单
@csrf_exempt
@require_http_methods(["POST"])
def print_by_xlsx(request,sheet_uuid):
    datasource = json.loads(request.body.decode())
    search = datasource.get('search',{})
    # 启动后台线程来执行耗时任务
    thread = Thread(target=print_by_xlsx_background_task, args=(datasource, sheet_uuid))
    thread.start()
    # 立即返回响应
    return ApiResponse.success("打印中，请等待，成功后请在钉钉中查找打印结果")

# 打印所有数据的逻辑代码
def print_by_xlsx_background_task(datasource,sheet_uuid):
    # print('datasource',datasource)
    current_page = 1
    page_size = 99
    all_report_data = []  # 用于存储所有页面的数据
    while True:
        report_data = yida_client.get_form_data_by_search_field(
            "FORM-0BC04FECE4F544B297D37901915570D2OEIY",
            admin_user_id,
            datasource["search"],
            # {
            # "dateField_lp92f309": datasource["record_date"],
            # "textField_lqetx3jq": datasource["salesman"],
            # },
            current_page=current_page,
            page_size=page_size
        )
        print(report_data)
        # 将获取的数据添加到all_report_data列表中
        all_report_data.extend(report_data)
        # 打印获取的数据长度
        print(len(report_data))
        # 检查是否还有更多的数据（即本次获取的数据长度是否小于page_size）
        if len(report_data) < page_size:
            break  # 如果没有更多数据，退出循环
        current_page += 1  # 准备获取下一页的数据
    # 打印总数据长度
    print(f"Total data length: {len(all_report_data)}")
    print_by_xlsx_utils(all_report_data,datasource,sheet_uuid)


# 打印指定的财务清单
@csrf_exempt
@require_http_methods(["POST"])
def print_Appoint_by_xlsx(request,sheet_uuid):
    datasource = json.loads(request.body.decode())
    # 启动后台线程来执行耗时任务
    thread = Thread(target=print_Appoint_by_xlsx_background_task, args=(datasource, sheet_uuid))
    thread.start()
    # 立即返回响应
    return ApiResponse.success("打印中，请等待，成功后请在钉钉中查找打印结果")

# 打印指定清单的逻辑代码
def print_Appoint_by_xlsx_background_task(datasource,sheet_uuid):
    # 打印总数据长度
    all_report_data = yida_client.get_form_items_by_id_list(
        "FORM-0BC04FECE4F544B297D37901915570D2OEIY",
        datasource['formInstanceIdList'],
        admin_user_id
    )
    print(all_report_data[0])
    print_by_xlsx_utils(all_report_data,datasource,sheet_uuid)




# 导出全部财务数据
@csrf_exempt
@require_http_methods(["POST"])
def print_financial_xlsx(request):
    # 解析JSON数据
    try:
        data = json.loads(request.body)
        search = data.get('search',{})
        name = data.get('name')
        # 启动后台线程来执行耗时任务
        thread = Thread(target=print_financial_xlsx_background_task, args=(search,name))
        thread.start()
        # 立即返回响应
        # "导出中，请等待，成功后请在钉钉中查找打印结果"
        return ApiResponse.success("导出中，请等待，成功后请在钉钉中查找打印结果")
    except json.JSONDecodeError:
        return JsonResponse({'error': '无效的JSON'}, status=400)

def print_financial_xlsx_background_task(search,name):
    all_report_data,total = yida_client.get_all_form_data_by_search_field(
        "FORM-0BC04FECE4F544B297D37901915570D2OEIY",
        admin_user_id,
        search,
    )
    print_financial_xlsx_utils(all_report_data,name)
    

# 导出指定财务数据
@csrf_exempt
@require_http_methods(["POST"])
def print_Appoint_financial_xlsx(request):
    # 解析JSON数据
    try:
        data = json.loads(request.body)
        # search = data.get('search',{})
        formInstanceIdList = data.get('formInstanceIdList',[])
        print("formInstanceIdList",formInstanceIdList)
        # return '1'
        # 启动后台线程来执行耗时任务
        thread = Thread(target=print_Appoint_financial_xlsx_background_task, args=(formInstanceIdList,))
        thread.start()
        # 立即返回响应
        # "导出中，请等待，成功后请在钉钉中查找打印结果"
        return ApiResponse.success("导出中，请等待，成功后请在钉钉中查找打印结果")
    except json.JSONDecodeError:
        return JsonResponse({'error': '无效的JSON'}, status=400)

def print_Appoint_financial_xlsx_background_task(formInstanceIdList):
    all_report_data = yida_client.get_form_items_by_id_list(
        "FORM-0BC04FECE4F544B297D37901915570D2OEIY",
        formInstanceIdList,
        admin_user_id
    )
    print_financial_xlsx_utils(all_report_data)
    

# 
@csrf_exempt
@require_http_methods(["POST"])
def saving_signature_photos(request):
    try:
        data = json.loads(request.body)
        user_dingtalk_id = data.get('user_dingtalk_id','')
        # print(user_dingtalk_id)
        all_report_data = yida_client.get_form_data_by_search_field(
            "FORM-861F9E6F4AAE4D73A255247BF7991765XAKG",
            admin_user_id,
            {
                "textField_lp0zbal4": user_dingtalk_id
            }
        )
        url = 'https://api.zjcxjc.cn/api/v1/digital-sign/get-personinfo-by-dingtalk-id'
        query_params = {
            'dingtalkUserId': user_dingtalk_id
        }
        # 发送GET请求并传递参数
        response = requests.get(url, params=query_params)
        if response.status_code == 200:
            # 解析响应内容
            data = response.json()
            key = f"{data['data']['personInformationPath']}sealfile.png"
        response = requests.get(all_report_data[0].form_data['digitalSignatureField_lp0tv65b'])
        if response.status_code == 200:
            # print(response.content)
            print(key)
            digital_bucket.put_object(key,response.content)
            sign_url = digital_bucket.sign_url("GET",key,600)
            return ApiResponse.success(sign_url)
    except json.JSONDecodeError:
        return JsonResponse({'error': '无效的JSON'}, status=400)
    

# --------------------------------------
# 配置函数-公共

# 打印清单的公共代码
# 传入all_report_data：获取到的项目信息流程的数据
# 调用财务流程表获取数据并且将数据写入到oss中并且返回url链接并创建新数据到打印表
def print_by_xlsx_utils(all_report_data,datasource,sheet_uuid):
    table_data = []
    for index,item in enumerate(all_report_data):
        text1 = item.form_data['textField_lp93kxwo']
        num1 = float(re.search(r'\d+(\.\d+)?', text1).group()) if re.search(r'\d+(\.\d+)?', text1) else 0
        text2 = item.form_data['textField_lp93kxwq']
        num2 = float(re.search(r'\d+(\.\d+)?', text2).group()) if re.search(r'\d+(\.\d+)?', text2) else 0
        timestamp_ms = item.form_data['dateField_lp92f309']
        # 将毫秒级时间戳转换为秒级时间戳
        timestamp_s = timestamp_ms / 1000
        # 使用 datetime 从秒级时间戳创建 datetime 对象
        dt_object = datetime.fromtimestamp(timestamp_s)
        # 将 datetime 对象格式化为字符串
        formatted_date = dt_object.strftime('%Y-%m-%d')
        table_data_item = [
            index+1,
            formatted_date,
            item.form_data['textField_lp93kxup'],
            item.form_data['textField_lphpacz4'],
            item.form_data['textField_lphpacz0'],
            num1,
            num2
        ]
        # print(table_data_item)
        table_data.append(table_data_item)
    with ThreadPoolExecutor(max_workers=2) as executor:
        future_to_item = {executor.submit(get_financial_data, item): item for item in table_data}
        for future in as_completed(future_to_item):
            try:
                # 确保任务完成，捕获并处理异常
                result = future.result()
            except Exception as e:
                print(f"Task generated an exception: {e}")
        print(table_data)
        table_data_num =  f'共{len(table_data)}单'
        # return ApiResponse.success(len(all_report_data))
        amount_data = sum([item[-1] for item in table_data if item])
        amount_zh_data = num_to_rmb(amount_data)
        df = pd.DataFrame(table_data)
        logger.info(sheet_uuid)
        sheet_path = os.path.join(tmp_path, f"{sheet_uuid}.xlsx")
        sheet_name = 'Sheet1'
        book = load_workbook(sheet_path)
        sheet = book[sheet_name]
        salesman = datasource["salesman"]
        insert_value_to_cell(sheet,"C2",salesman)
        start_date = datasource["record_date"][0]
        end_date = datasource["record_date"][1]
        start_date = datetime.fromtimestamp(start_date/1000).strftime('%Y年%m月%d')
        end_date = datetime.fromtimestamp(end_date/1000).strftime('%Y年%m月%d')
        insert_value_to_cell(sheet,"E2",f"{start_date} 至 {end_date}")
        now_date = datetime.now().strftime('%Y年%m月%d')
        insert_value_to_cell(sheet,"H2",now_date)
        insert_value_to_cell(sheet,"G8",amount_data)
        insert_value_to_cell(sheet,"D8",amount_zh_data)
        insert_value_to_cell(sheet,"A8",table_data_num)
        # 在插入行之前，记录所有合并单元格的范围
        row_heights = {row: sheet.row_dimensions[row].height for row in range(1, sheet.max_row + 1)}
        merged_cells_ranges = [str(merged_cell) for merged_cell in sheet.merged_cells.ranges]
        # 删除原合并单元格设置以避免插入时出现错误
        for merged_cell in merged_cells_ranges:
            sheet.unmerge_cells(merged_cell)
            
        df_rows = df.shape[0]
        startrow = 5
        sheet.insert_rows(startrow, df_rows)
        for i, row in df.iterrows():
            for j, value in enumerate(row):
                cell = sheet.cell(row=startrow + i, column=j + 1, value=value)
                cell.border = thin_border

        # 重新设置行高
        for row, height in row_heights.items():
            if row >= 4:  # 调整新增行之后的行高
                sheet.row_dimensions[row + df_rows].height = height
            else:  # 保留新增行之前的行高
                sheet.row_dimensions[row].height = height
        # 重新合并单元格
        for merged_cell in merged_cells_ranges:
            min_col, min_row, max_col, max_row = range_boundaries(merged_cell)
            # 调整行号以反映新插入的行
            if min_row >= 4:
                min_row += df_rows
                max_row += df_rows
            new_range = f"{openpyxl.utils.get_column_letter(min_col)}{min_row}:{openpyxl.utils.get_column_letter(max_col)}{max_row}"
            sheet.merge_cells(new_range)
        save_sheet_path = os.path.join(tmp_path, f"{sheet_uuid}_print.xlsx")
        # 保存更改
        book.save(save_sheet_path)
        key = f"file_tmp/{datetime.now().strftime('%Y%m')}/{uuid.uuid4()}.xlsx"
        bucket.put_object_from_file(key,save_sheet_path)
        sign_url = bucket.sign_url("GET",key,600)
        # return ApiResponse.success(sign_url)
        yida_client.create_form_data(
            "FORM-C72E2260C4154109B9821B99E3430584V2WE",
            admin_user_id,
            {"textField_lurphsap": sign_url,
            "employeeField_m9c15jgj":[yida_client.admin_user_id]},
        )

# 获取财务数据并格式化 - 打印清单
def get_financial_data(item):
    financial_data = yida_client.get_form_data_by_search_field(
        "FORM-BAFAA96000BA4C44A0C8F3256EB00407RP4T",
        admin_user_id,
        {"textField_ltmbnezf": item[2]},
        current_page=1, page_size=1
    )
    # print('--report>>>>>>>',financial_data[0].form_data['numberField_lv0lyit9'])
    item.extend([
        float(financial_data[0].form_data['numberField_lv0lyit9_value']) if financial_data[0].form_data['numberField_lv0lyit9_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyita_value']) if financial_data[0].form_data['numberField_lv0lyita_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyitb_value']) if financial_data[0].form_data['numberField_lv0lyitb_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyitc_value']) if financial_data[0].form_data['numberField_lv0lyitc_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyite_value']) if financial_data[0].form_data['numberField_lv0lyite_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyitf_value']) if financial_data[0].form_data['numberField_lv0lyitf_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyith_value']) if financial_data[0].form_data['numberField_lv0lyith_value'] else 0,
        float(financial_data[0].form_data['numberField_lv0lyiti_value']) if financial_data[0].form_data['numberField_lv0lyiti_value'] else 0,
    ])
    if not item:
        print(f">>>>>>>>{item[2]}")
    return item  # 返回更新后的item


def insert_value_to_cell(sheet, cell_coordinate, value):
    """在指定单元格内插入数据"""
    # 将单元格坐标（如'E2'）转换为行列数（如(2, 5)）
    row, column = coordinate_to_tuple(cell_coordinate)
    sheet.cell(row=row, column=column, value=value)


# 导出数据的公共代码
# 传入all_report_data：获取到的项目信息流程的数据
# 调用财务流程表获取数据并且将数据写入到oss中并且返回url链接并创建新数据到打印表
def print_financial_xlsx_utils(all_report_data,name):
    data_to_write = []
    headers = [
        '登记日期', '归属地', '县级归属地', '委托方', '工程名称', '报告编号',
        '总面积', '单价', '总检测费', '公司收款', '业务员收款', '管理费',
        '税额', '其他款项', '其他税额', '社保金额', '结算金额', '收款状态'
    ]
    # print(report_code_list)
    # 使用 Queue 来安全地从线程收集数据
    results_queue = Queue()
    if(len(all_report_data)> 0):
        with ThreadPoolExecutor(max_workers=1) as executor:
            # 提交所有报告数据到线程池，开始处理
            futures = [executor.submit(process_report_data_wrapper, report_data, results_queue) for report_data in all_report_data]
            # 等待所有线程处理完成
            for future in as_completed(futures):
                try:
                    result = future.result()
                except Exception as exc:
                    print(f'处理报告数据时发生错误: {exc}')
        data_to_write = list(results_queue.queue)
        print('data_to_write',data_to_write)
        df = pd.DataFrame(data_to_write, columns=headers)
        # 写入Excel文件
        output = io.BytesIO()
        df.to_excel(output, index=False, engine='openpyxl')
        output.seek(0)
        print(f'数据已写入缓存')
        # 上传oss
        current_date = datetime.now()
        formatted_date = current_date.strftime('%Y%m')
        file_name = f'{name if name else "financial_report"}-{datetime.now().strftime("%Y%m%d%H%M%S")}.xlsx'
        key = f'file_tmp/{formatted_date}/{file_name}'
        bucket.put_object(key,output.getvalue())
        sign_url = bucket.sign_url("GET",key,24*3600)
        # return ApiResponse.success(sign_url)
        yida_client.create_form_data(
            "FORM-C72E2260C4154109B9821B99E3430584V2WE",
            admin_user_id,
            {"textField_lurphsap": sign_url,
             "employeeField_m9c15jgj":[yida_client.admin_user_id]},
        )
    else:
        return JsonResponse({'error': '无参数'}, status=400)

def process_report_data_wrapper(report_data, results_queue):
    try:
        result = process_report_data(report_data, results_queue)
        return result
    except Exception as exc:
        print(f"处理报告数据时发生错误: {exc}")
        return None
# 获取财务数据并格式化 - 导出数据
def process_report_data(report_data,results_queue):
    report_form_data = report_data.form_data
    cache_key = f"xu_yida:chengxiang:form_data:{finicial_form_uuid}:{report_form_data['textField_lp93kxup']}"
    financial_data_res_cache = redis_client.get(cache_key)
    if financial_data_res_cache:
        print("从缓存读取")
        financial_data = json.loads(financial_data_res_cache)
        if(isinstance(financial_data,str)):
            financial_data = json.loads(financial_data)
        process_status = financial_data.get("process_status")
        if not process_status:
            redis_client.delete(cache_key)
            return process_report_data(report_data,results_queue)
        collection_status = '未收款'
        if process_status =='待预算':
            collection_status = '未收款'
        elif process_status =='结算':
            collection_status = '部分已收'
        elif process_status =='结清':
            collection_status = '已收'
    else:
        print("从表单读取")
        financial_data_res = yida_client.get_form_data_by_search_field(
            "FORM-BAFAA96000BA4C44A0C8F3256EB00407RP4T",
            admin_user_id,
            [
                {
                "type": "TEXT",
                "operator": "eq",
                "componentName": "TextField",
                "key": "textField_ltmbnezf",
                "value": report_form_data['textField_lp93kxup']
                }
            ]
            )
        if not financial_data_res:
            financial_data = None
        else:
            financial_data = financial_data_res[0]
            cache_data = {
                "form_data": financial_data.form_data,
                "form_instance_id":financial_data.form_instance_id,
                "process_status":'待预算',
            }
            financial_InstanceId = financial_data.form_instance_id
            print('financial_InstanceId',financial_InstanceId)
            # 财务表单————审批状态
            if not financial_InstanceId:
                results_queue.put({
                    '报告编号': report_form_data['textField_lp93kxup'],
                })
                return
            financial_process = yida_client.get_approve_history(
                financial_InstanceId,
                admin_user_id
            )
            # print('financial_process',financial_process)
            # 收款状态
            collection_status = "未知"
            for financial_process_item in financial_process:
                if financial_process_item.type == 'TODO':
                    show_name = financial_process_item.show_name
                    if show_name =='待预算':
                        cache_data["process_status"] = '待预算'
                        collection_status = '未收款'
                    elif show_name =='结算':
                        cache_data["process_status"] = '结算'
                        collection_status = '部分已收'
                    elif show_name =='结清':
                        cache_data["process_status"] = '结清'
                        collection_status = '已收'
                    break
            value = json.dumps(cache_data,skipkeys=True)
            key = f"xu_yida:chengxiang:form_data:{finicial_form_uuid}:{financial_data.form_data.get('textField_ltmbnezf')}"
            print("已记录缓存")
            redis_client.set(key,value,ex=None)
    # 登记日期
    date_of_registration = report_form_data['dateField_lp92f309']
    # 转换为秒级别的时间戳
    timestamp_s = date_of_registration / 1000
    # 时区差异，对于北京时间是UTC+8
    tz_beijing = timezone(timedelta(hours=8))
    # 使用时区感知的方式来转换时间戳
    date = datetime.fromtimestamp(timestamp_s, tz=tz_beijing)
    # 格式化日期
    date_str = date.strftime('%Y/%m/%d')
    # 地区
    area = report_form_data['cascadeSelectField_lpgahbwq']
    # 归属地
    Attribution = '省外'
    # 县级归属地
    county = '无'
    if(len(area)>1):
        Attribution = area[1]
        county = area[2]
    elif(len(area)==1):
        Attribution = area[0]
    else:
        Attribution = ''
    # 委托方
    clients = report_form_data.get("textField_lphpacz4")
    # 工程名称
    project_name = report_form_data.get("textField_lphpacz0")
    # 报告编号 report_code
    report_code = report_form_data.get("textField_lp93kxup")
    # 总面积
    total_area = report_form_data.get("textField_lp93kxwo")
    if total_area == '':
        total_area = '0'  
    # 单价
    price = report_form_data.get("textField_lp93kxwp")
    if price == '':
        price = '0' 
    if financial_data:
        if (isinstance(financial_data,dict)):
            financial_form_data = financial_data.get("form_data")
        else:
            financial_form_data = financial_data.form_data
    else:
        financial_form_data = {}
        collection_status = '未收款'
    # 总检测费
    if(collection_status == "未收款"):
        total_price = report_form_data.get('textField_lp93kxwq',0)
    else:
        total_price = financial_form_data.get("numberField_lv0lyit8_value",0)
    # 公司收款 companyCollection
    companyCollection = financial_form_data.get('numberField_lv0lyit9_value',0)
    # 业务员收款 salesmanCollection
    salesmanCollection = financial_form_data.get('numberField_lv0lyita_value',0)
    # 管理费 managementCost
    managementCost = financial_form_data.get('numberField_lv0lyitb_value',0)
    # 税额 receiptTaxAmount
    receiptTaxAmount = financial_form_data.get('numberField_lv0lyitc_value',0)
    # 其他款项 otherAmount
    otherAmount = financial_form_data.get('numberField_lv0lyite_value',0)
    # 其他税额 otherTaxAmount
    otherTaxAmount = financial_form_data.get('numberField_lv0lyitf_value',0)
    # 社保金额 socialSecurityAmount
    socialSecurityAmount = financial_form_data.get('numberField_lv0lyith_value',0)
    # 结算金额 settlementAmountTotal
    settlementAmountTotal = financial_form_data.get('numberField_lv0lyiti_value',0)
    data_dict = {
        '登记日期': date_str,
        '归属地': Attribution,
        '县级归属地': county,
        '委托方': clients,
        '工程名称': project_name,
        '报告编号': report_code,
        '总面积': total_area,
        '单价': price,
        '总检测费': total_price,
        '公司收款': companyCollection,
        '业务员收款': salesmanCollection,
        '管理费': managementCost,
        '税额': receiptTaxAmount,
        '其他款项': otherAmount,
        '其他税额': otherTaxAmount,
        '社保金额': socialSecurityAmount,
        '结算金额': settlementAmountTotal,
        '收款状态': collection_status
    }
    print('数据',data_dict)
    results_queue.put(data_dict)



@csrf_exempt
@require_http_methods(["POST"])
def generate_report(request,uuid_string):
    try:
        report_model = RepModel.objects.get(uuid=uuid_string)
    except RepModel.DoesNotExist:
        return ApiResponse.fail(message="未找到模板.")
    datasource: dict[str, any] = json.loads(request.body)
    render_data = datasource["render_data"]
    attachment_info = datasource["attachment_info"]
    download_url = attachment_info.get("download_url")
    full_download_url = yida_client.get_full_download_url(
        user_id=admin_user_id, download_url=download_url)
    response = requests.get(full_download_url.body.result)
    if response.status_code == 200:
        file_content = response.content
        render_record = DocxRenderRecord(
            render_data=render_data,
            company_name="浙江城乡检测",
            model_id=report_model.id
        )
        report_path = rf"out-pdf/{datetime.now().strftime('%Y%m')}/{render_record.task_id}"
        create_directories_if_not_exist(
            [rf"{tmp_path}/{report_path}"])  # 创建报告缓存路径
    try:
        tmp_file_path = rf"{tmp_path}/{report_model.path}"
        if not os.path.exists(tmp_file_path):
            create_directories_if_not_exist([tmp_file_path])
            print(f"缓存模板不存在，从oss下载>>>>>>>")
            if bucket.object_exists(report_model.path):
                print("文件已找到>>>>>>")
            bucket.get_object_to_file(report_model.path, tmp_file_path)
            print(f"模板下载成功>>>>>>>")
        else:
            print(f"本地模板文件已找到{tmp_file_path}")

        # thread = threading.Thread(target=generateReportPdf)
        # thread.start()
        print(f"报告生成中>>>>>>>")
        return ApiResponse.success(message=f"报告{render_record.task_id}数据已导入,正在生成报告，请稍后")
    except ValueError:
        return ApiResponse.fail(message="Invalid UUID format.")
    except Exception:
        return ApiResponse.fail(message=f"报告生成失败")
    

def get_fake_sign_report(request):
    '''查看伪签名报告'''
    report_code = request.GET.get('reportCode')
    report = Report.objects.get(report_code=report_code)
    if not report:
        return ApiResponse.fail(message=rf"报告未生成，请在发起签署后打印")
    if report.digital_sign_order_no:
        result = xm_digital_sign_client.get_completed_sign_records(report.digital_sign_order_no)
        if result.get("code") == 200:
            completed_records = result.get("data")
            participants = [{
                "dingtalkUserId":record.get("dingtalkUserId"),
                "coordinate":record.get("coordinate"),
            } for record in completed_records if not record.get("sealFilePath")]
    else:
        participants = []
    fake_pdf_path = fake_sign(report.report_path,participants)
    params = {'response-content-disposition': 'inline'}
    url = bucket.sign_url('GET', fake_pdf_path, 3600, params=params)
    return ApiResponse.success(data=url)
# 返回完整报告内容
def get_whole_report(request):
    report_code = request.GET.get('reportCode')
    is_admin = request.GET.get('isAdmin',None)
    report = Report.objects.get(report_code=report_code)
    if report.digital_sign_order_no:
        if not is_admin:
            sign_order_res = xm_digital_sign_client.get_sign_order(report.digital_sign_order_no)
            if sign_order_res.get("code") == 200:
                if sign_order_res.get("data").get("completedDate"):
                    is_admin = True
        if is_admin:
            result = xm_digital_sign_client.get_signed_pdf(report.digital_sign_order_no)
            if result.get("code") == 200:
                encrypt_report_url = encrypt_report(result.get("data"))
                return ApiResponse.success(message=rf"报告已找到", data=encrypt_report_url)
            else:
                return ApiResponse.fail(message=result.get("message"))
    path = rf"{report.report_path}/whole.pdf"
    path_bak = rf"{report.report_path}/whole_print.pdf"
    # 创建限速下载文件的签名URL, 有效期60s。
    params = {'response-content-disposition': 'inline'}
    if (bucket.object_exists(path)):
        url = bucket.sign_url('GET', path, 3600, params=params)
        encrypt_report_url = encrypt_report(url)
        return ApiResponse.success(message=rf"报告已找到", data=encrypt_report_url)
    elif (bucket.object_exists(path_bak)):
        url = bucket.sign_url('GET', path_bak, 3600, params=params)
        encrypt_report_url = encrypt_report(url)
        return ApiResponse.success(message=rf"报告已找到", data=encrypt_report_url)
    else:
        return ApiResponse.fail(message=rf"报告未找到")







@csrf_exempt
@require_http_methods(["POST"])
# 批量生成报告
def batch_generation_report(request):
    try:
        data = json.loads(request.body)
        userId = data.get("uuid", "")                # 发起人uuid
        number_str = data.get("number", "1")       # 数量
        try:
            number = int(number_str)  # 如果是整数
        except ValueError:
            number = 1  # 如果无法转换，给出默认值
        form_inst_id = data.get("form_inst_id", "")  
        print(f'参数--->formInstId: {form_inst_id}, 发起人userId: {userId}, 数量: {number}')
        report_data = yida_client.get_form_items_by_ids(
            "FORM-0BC04FECE4F544B297D37901915570D2OEIY",
            form_inst_id,
            userId
        )
        form_data_json = report_data[0].form_data
        thread = Thread(target=batch_generation_report_background_task, args=(userId, number, form_data_json))
        thread.start()
        return ApiResponse.success(message=rf"正在批量生成")
    except Exception as e:
        return  ApiResponse.fail(message=rf"批量生成失败")

# 
def batch_generation_report_background_task(userId,number,form_data_json):
    max_retries = 3
    report_code = form_data_json['textField_lp93kxup']
    # 判断report_code末五位是否是数字
    if report_code[-5:].isdigit():
        report_code_last = report_code[:-5]
    else:
        report_code_last = report_code
    # print('编号--->',report_code_last)
    form_data_json['textField_lp93kxup'] = report_code_last
    form_data_json['numberField_lqd7xome'] = 1
    form_data_json['textField_lvg2c3u6'] = ''
    form_data_json['textField_m0wjwsev'] = str(uuid.uuid4())
    filtered_res = {key: value for key, value in form_data_json.items() if key.endswith('_id')}
    for key, value in filtered_res.items():
        # print(f"{key}: {value}")
        form_data_json[key.split('_id')[0]] = value
    # 删除对应的键
    for key in filtered_res.keys():
        del form_data_json[key]
    # print('修改后的', form_data_json)
    for index in range(number-1):
        print('index--->',index)
        retries = 0
        while retries < max_retries:
            try:
                # 发起新流程
                yida_client.create_process_instance(
                    "FORM-0BC04FECE4F544B297D37901915570D2OEIY",
                    userId,
                    form_data_json,
                    'TPROC--U0A66091AZQGSDPIFBEQP8HN89KL39DYDE7QLO7'
                )
                break  # 成功则跳出循环
            except Exception as e:
                print(f"重试 {retries + 1} 失败: {str(e)}")
                retries += 1
                time.sleep(1)  # 等待1秒再重试
        if retries == max_retries:
            logger.info(f"编号创建失败，已达到最大重试次数。")
            

@csrf_exempt
@require_http_methods(["GET"])
def update_bzy(request):
    bzy_name = request.GET.get('name')
    form_uuid = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"
    if not bzy_name:
        return ApiResponse.fail("请选择需要同步的编制员")
    person_form_uuid = "FORM-861F9E6F4AAE4D73A255247BF7991765XAKG"
    person_res = yida_client.get_form_data_by_search_field(person_form_uuid,admin_user_id,[
        {
          "type": "TEXT",
          "operator": "eq",
          "componentName": "TextField",
          "key": "textField_lp0tv654",
          "value": bzy_name
        }
      ])
    person_instance = person_res[0].form_data
    person_id = person_instance.get("textField_lp0zbal4")
    Thread(target=update_bzy_task, args=(bzy_name,form_uuid,person_id)).start()
    return ApiResponse.success(f"发起同步编制人任务")

def update_bzy_task(bzy_name,form_uuid,person_id):
    form_instances,total = yida_client.get_all_form_data_by_search_field(form_uuid,admin_user_id,[
      {
        "type": "TEXT",
        "operator": "eq",
        "componentName": "TextField",
        "key": "textField_lrd6lxm1",
        "value": bzy_name
      }
    ])
    for index,item in enumerate(form_instances):
        form_data = item.form_data
        print(f"正在处理第{index+1}份报告：{form_data.get('textField_lp93kxup')}")
        form_inst_id = item.form_instance_id
        name = form_data.get('textField_lrd6lxm1') # 编制人name
        bzy_select = form_data.get('selectField_lqwcqyd0') #编制员
        bzy_select_id = form_data.get('selectField_lqwcqyd0_id')
        if (not bzy_select_id) or (name == bzy_select) or (bzy_select_id == person_id):
            continue
        else:
            result = yida_client.update_form_data_by_id(form_uuid,admin_user_id,form_inst_id,{
                "selectField_lqwcqyd0":person_id,
            })
            print(f"result>>>>>>{result}")
@csrf_exempt
@require_http_methods(["GET"])
def archive(request):
    start_time = request.GET.get('start_time')
    end_time = request.GET.get('end_time')
    form_uuid = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"
    if not start_time or not end_time:
        return ApiResponse.fail("请选择时间范围")
    form_instances = yida_client.get_form_data_by_date_range(
        form_uuid=form_uuid,
        userId=admin_user_id,
        start_time=start_time,
        end_time=end_time, # 不包含该时间
        dynamic_order=None,
        )
    Thread(target=start_backup_task, args=(form_instances,form_uuid)).start()
    return ApiResponse.success(f"成功发起备份任务，共{len(form_instances)}个任务")

def archive_v2(request):
    # reports = Report.objects.filter(is_backup=False).order_by('-created_at')[:1000]
    threading.Thread(target=archive_task_2, args=()).start()
    return ApiResponse.success(f"成功发起备份任务")


def archive_task_2():
    for i in range(10):
        print(f"第{i+1}次执行")
        result = yida_client.get_form_data_by_search_field(report_form_uuid,
                                          admin_user_id,
                                          [
                                              {
                                                "type": "TEXT",
                                                "operator": "eq",
                                                "componentName": "SelectField",
                                                "key": "selectField_m4wf9ayu",
                                                "value": "否"
                                              },
                                              { "key": "currentNodeName", 
                                                "value": ['待审核', '总工审核', "待归档", '最终审核'], 
                                                "type": "ARRAY", "operator": "contains", "componentName": "TextField" 
                                              },
                                          ],
                                          page_size=100)
        for report in result:
            start_backup_task_test(report,report_form_uuid)


def archive_task(reports:list):
    form_uuid = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"
    for report in reports:
        report_code = report.report_code
        result = yida_client.get_form_data_by_search_field(form_uuid,admin_user_id,[
          {
            "type": "TEXT",
            "operator": "eq",
            "componentName": "TextField",
            "key": "textField_lp93kxup",
            "value": report_code
          }
        ])
        print(f"report_code>>>>>>{report_code}")
        start_backup_task(result,form_uuid)

def start_backup_task(form_instances,form_uuid):
    for index,item in enumerate(form_instances):
        # if index < 166:
        #     continue
        print(f"正在处理第{index+1}份报告：{item.form_data.get('textField_lp93kxup')}")
        logger.info(f"正在处理第{index+1}份报告：{item.form_data.get('textField_lp93kxup')}")
        try:
            report = Report.objects.get(report_code=item.form_data.get('textField_lp93kxup'))
        except Report.DoesNotExist:
            print(f"未找到报告：{item.form_data.get('textField_lp93kxup')}")
            continue
        except Report.MultipleObjectsReturned:
            print(f"找到多个报告：{item.form_data.get('textField_lp93kxup')}")
            reports = Report.objects.filter(report_code=item.form_data.get('textField_lp93kxup')).order_by('-created_at')
            if reports.exists():
                report = reports.first()
                print(f"找到多个报告，取最新报告：{report}")
            else:
                print(f"未找到报告：{item.form_data.get('textField_lp93kxup')}")
                continue
        except Exception as e:
            print(f"处理报告时发生错误：{e}")
            continue
        report_path = report.report_path
        print(f"正在备份报告：{report.report_code}")
        try:
            bak_attachment(item,"attachmentField_lpb2cdkb",report_path,form_uuid)
            bak_attachment(item,"attachmentField_lpb2cdka",report_path,form_uuid)
            bak_attachment(item,"attachmentField_lpb2cdkd",report_path,form_uuid)
            bak_attachment(item,"attachmentField_lpb2cdkf",report_path,form_uuid)
            bak_attachment(item,"attachmentField_lqrz4ehj",report_path,form_uuid)
        except Exception as e:
            print(f"未知错误：{e}")
            continue
        report.is_backup = True
        report.save()
        print("备份成功")
        time.sleep(3)
    

def bak_attachment(form_inst_data,field_name,report_path,form_uuid,retry=3):
    try:
        print("备份地址"+report_path)
        if field_name not in form_inst_data.form_data:
            print(f"{field_name}该字段无值")
            return
        attachments = json.loads(form_inst_data.form_data[field_name])
        new_attachments = []
        for index,attachment in enumerate(attachments):
            download_url:str = attachment.get("downloadUrl")
            if download_url.startswith("https://api.zjxmyq.cn") or download_url.startswith("https://api.zjcxjc.cn"):
                print(f"{field_name}已备份，无需重复备份")
                new_attachments.append(attachment)
                continue
            full_download_url = yida_client.get_full_download_url(admin_user_id,download_url,True)
            response = requests.get(full_download_url.body.result)
            if response.status_code == 200:
                file_content = response.content
                oss_path = f"{report_path}/{field_name}/{index}-{attachment.get('name')}"
                bucket.put_object(oss_path, file_content)
                xm_url = f"https://api.zjcxjc.cn/api/v1/yida-app/common/download_file/{oss_path}"
                new_attachment = {
                        "downloadUrl": xm_url,
                        "name": attachment.get('name'),
                        "previewUrl": xm_url,
                        "url": xm_url,
                        "ext": attachment.get('name').split('.')[-1]
                    }
                new_attachments.append(new_attachment)
        yida_client.update_form_data_by_id(form_uuid, admin_user_id, form_inst_data.form_instance_id, {
                    field_name: new_attachments
                })
        print(f"{field_name}备份成功")
    except Exception as e:
        print(f"宜搭接口调用错误：{e}")
        retry -= 1
        if retry > 0:
            bak_attachment(form_inst_data,field_name,report_path,form_uuid,retry)

@csrf_exempt
@require_http_methods(["POST"])
def modify_report(request):
    # 获取原始请求体数据
    req_data = json.loads(request.body)  # 假设请求体是JSON格式
    report_code_arr = req_data.get("reportCodeArr")
    update_data = req_data.get("updateData")
    for report_code in report_code_arr:
        print(f"report_code is {report_code}")
        res = yida_client.update_form_data_by_field(
            form_uuid=report_form_uuid,
            userId=req_data.get("user_id",admin_user_id),
            search_field=[{
                  "type": "TEXT",
                  "operator": "eq",
                  "componentName": "TextField",
                  "key": "textField_lp93kxup",
                  "value": report_code
                }],
            update_field=update_data
            )
        if (res != "success"):
            return ApiResponse.fail(message=f"报告{report_code}修改失败")
    return ApiResponse.success(message="修改成功")
# 超过一月未到总工冻结
@csrf_exempt
@require_http_methods(["GET"])    
def refuse_to_register(request):
    over_time_ids = get_over_time_data()# 30天内未提交审核报告
    Thread(target=refuse_to_register_task, args=(over_time_ids,"报告审核超时")).start()
    over_time_judiciary_ids = get_judiciary_over_time_data()# 60天内未提交审核司法报告
    Thread(target=refuse_to_register_task, args=(over_time_judiciary_ids,"司法报告审核超时")).start()
    over_time_archive_ids = get_archive_over_time_data() # 10天未归档的报告
    Thread(target=refuse_to_register_task, args=(over_time_archive_ids,"报告归档超时")).start()
    return ApiResponse.success(message='正在冻结账号...')

def get_over_time_data():
    '''获取超时30天的报告'''
    timestamp_30 = int((datetime.now() - timedelta(days=30)).timestamp() * 1000)
    form_inst_ids,_ = yida_client.get_all_ids_by_search_field(report_form_uuid,
                                            admin_user_id,
                                            [{
                                                "key": "currentNodeName",
                                                "value": ["待写报告", "待审核"],
                                                "type": "ARRAY",
                                                "operator": "contains",
                                                "componentName": "TextField"
                                            },
                                            {
                                                "key": "dateField_lp92f309",
                                                "value": timestamp_30,
                                                "type": "DOUBLE",
                                                "operator": "lt",
                                                "componentName": "DateField"
                                            },
                                            {
                                                "key":"selectField_lp9egpd9",
                                                "value":["材料","鉴定","金华分公司","衢州公司","典型","比对","桥隧","幕墙","节能","地基","通用","评估","空气","结构","钢构","监测"],
                                                "type":"ARRAY",
                                                "operator":"contains",
                                                "componentName":"SelectField"
                                            }
                                            ])
    return form_inst_ids

def get_judiciary_over_time_data():
    '''获取超时60天的司法报告'''
    timestamp_60 = int((datetime.now() - timedelta(days=90)).timestamp() * 1000)
    form_inst_ids,_ = yida_client.get_all_ids_by_search_field(report_form_uuid,
                                            admin_user_id,
                                            [{
                                                "key": "currentNodeName",
                                                "value": ["待写报告", "待审核"],
                                                "type": "ARRAY",
                                                "operator": "contains",
                                                "componentName": "TextField"
                                            },
                                            {
                                                "key": "dateField_lp92f309",
                                                "value": timestamp_60,
                                                "type": "DOUBLE",
                                                "operator": "lt",
                                                "componentName": "DateField"
                                            },       
                                            {
                                                "key":"selectField_lp9egpd9",
                                                "value":["产品","纠纷","司法","设计","造价"],
                                                "type":"ARRAY",
                                                "operator":"contains",
                                                "componentName":"SelectField"
                                            }
                                            ]
                                            )
    return form_inst_ids


def get_archive_over_time_data():
    '''获取超时10天未归档的报告'''
    timestamp_now = int(datetime.now().timestamp() * 1000)
    form_inst_ids,_ = yida_client.get_all_ids_by_search_field(report_form_uuid,
                                            admin_user_id,
                                            [{
                                                "key": "currentNodeName",
                                                "value": ["待归档"],
                                                "type": "ARRAY",
                                                "operator": "contains",
                                                "componentName": "TextField"
                                            },
                                            {
                                                "key": "dateField_m1in1ghn",
                                                "value": timestamp_now,
                                                "type": "DOUBLE",
                                                "operator": "lt",
                                                "componentName": "DateField"
                                            }
                                            ]
                                            )
    return form_inst_ids


def refuse_to_register_task(all_data, refuse_reason:str):
    '''冻结账号'''
    unique_data = []
    for i, data in enumerate(all_data):
        cache_key = f"xu_yida:chengxiang:timeout_freeze_compiler:{data}"
        value = redis_client.get(cache_key)
        if value != '1':
            unique_data.append(data)
            redis_client.set(cache_key, '1', ex=5*24*60*60)  # 10天的秒数
    need_freeze_personnel = []   # 需要冻结的人
    for index, item in enumerate(unique_data):
        examine_approve_item = yida_client.get_form_items_by_ids(
            report_form_uuid,
            item,
            admin_user_id   
        )
        if examine_approve_item:
            # need_freeze_personnel.extend(examine_approve_item[0].form_data['multiSelectField_lqwcqyd1']) # 冻结组
            need_freeze_personnel.append(examine_approve_item[0].form_data.get("selectField_lqwcqyd0_id")) # 冻结编制员
    # 去重
    need_freeze_personnel_norepetition = list(dict.fromkeys(need_freeze_personnel))
    print('需冻结的编制员--->',need_freeze_personnel_norepetition)
    print('len--->',len(need_freeze_personnel_norepetition))
    
    # 需过滤掉的指定id
    need_filtered_id = [
        '132058133925879495',
        '4302516026430609',
        '383267142424342951'
    ]
    for index,item in enumerate(need_filtered_id):
        if item in need_freeze_personnel_norepetition:
            need_freeze_personnel_norepetition.remove(item)
    print('过滤后需要冻结的编制员--->',need_freeze_personnel_norepetition)
    print('len--->',len(need_freeze_personnel_norepetition))
    
    for index, item in enumerate(need_freeze_personnel_norepetition):
        logger.info('冻结人员--->',item)
        try:
            res = yida_client.update_form_data_by_field(
                'FORM-861F9E6F4AAE4D73A255247BF7991765XAKG',
                admin_user_id,
                {
                    "textField_lp0zbal4":item
                },
                {
                    "selectField_lygntf4y":"冻结",
                    "textField_m204ou0w":refuse_reason
                }
            )
            if res == "success":
                # 消息通知
                notify_res = yida_client.create_form_data("FORM-82A68C4460D545F0B252F230322C7D00X96R",admin_user_id,{
                    "employeeField_m5amnoi4":[item],
                    "textField_m5anuqz3":"通知",
                    "textareaField_m5amnoi5":f"您的账号已被冻结，原因：{refuse_reason}"
                })
                logger.info(f"消息通知结果：{notify_res}")

        except Exception as e:
            logger.error(e)
    

  
# 更正申请  
@csrf_exempt
@require_http_methods(["GET"])
def modify_application(request):
    start_report = request.GET.get('start_report')
    end_report = request.GET.get('end_report')
    # 提取前缀和数字部分
    start_prefix = start_report[:-5]
    end_prefix = end_report[:-5]
    try:
        start_num = int(start_report[-5:])
        end_num = int(end_report[-5:])
    except ValueError:
        return ApiResponse.fail(message='Invalid report numbers')
    # 检查前缀是否一致
    if start_prefix != end_prefix:
        return ApiResponse.fail(message='The prefixes of start_report and end_report must be the same')
    # 生成包括start_report和end_report在内的所有编号
    report_numbers = [f"{start_prefix}{str(num).zfill(5)}" for num in range(start_num, end_num + 1)]
    thread = Thread(target=modify_application_task, args=(report_numbers,))
    thread.start()
    return ApiResponse.success(message='正在进行更正,请稍等。。。')

def modify_application_task(report_numbers):
    print('report_numbers-->',report_numbers)
    for index, item in enumerate(report_numbers):
        print('----->',item)           
        form_inst_id =  yida_client.get_ids_by_search_field(
            'FORM-0BC04FECE4F544B297D37901915570D2OEIY',
            admin_user_id,
            {
                "textField_lp93kxup":item
            }
        )
        print('form_inst_id--->',form_inst_id)
        report_form = yida_client.get_form_items_by_ids(
            'FORM-0BC04FECE4F544B297D37901915570D2OEIY',
            form_inst_id[0],
            admin_user_id,
        )
        print(report_form[0].form_data['textField_ltmlzgdv'])            
            
        try:
            report_form_json = json.loads(report_form[0].form_data['textField_ltmlzgdv'])
            if 'report_code' in report_form_json:
                print('json中有report_code',report_form_json['report_code'])
                match = re.search(r'G(\d+)', report_form_json['report_code'])
            else:
                print('json中没有report_code')
                match = re.search(r'G(\d+)', item)
                
            if match:
                number_after_g = int(match.group(1)) + 1
                new_report_code = re.sub(r'G(\d+)', f'G{number_after_g}', report_form_json['report_code'])
                print('有match',match,number_after_g,new_report_code)
            else:
                new_report_code = item.split('-')[0] + 'G1'+'-'+item.split('-')[1]+'-'+item.split('-')[2]
            report_form_json['report_code'] = new_report_code
            print("JSON解析成功:", report_form_json)
        except json.JSONDecodeError:
            print("解析错误：提供的字符串不是有效的JSON格式")
            match = re.search(r'G(\d+)', item)
            if match:
                number_after_g = int(match.group(1)) + 1
                new_report_code = re.sub(r'G(\d+)', f'G{number_after_g}', item)
            else:
                new_report_code = item.split('-')[0] + 'G1'+'-'+item.split('-')[1]+'-'+item.split('-')[2]
            report_form_json = {
                "report_code":new_report_code
            }
        yida_client.update_form_data_by_id(
            'FORM-0BC04FECE4F544B297D37901915570D2OEIY',
            admin_user_id,
            form_inst_id[0],
            {
                "textField_ltmlzgdv":json.dumps(report_form_json)
            }
        )



# 生成报告封面
@csrf_exempt
@require_http_methods(["POST"])
def generate_base_report(request, uuid_string):
    try:
        if uuid_string != "nocover":
            report_model = RepModel.objects.get(uuid=uuid_string)
    except RepModel.DoesNotExist:
        return ApiResponse.fail(message="未找到模板.")
    datasource: dict[str, any] = json.loads(request.body)
    form_uuid = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"
    form_inst_id = datasource["formInstId"]  # 获取数据源中的表单实例ID
    form_instances = yida_client.get_form_items_by_ids(form_uuid, form_inst_id, admin_user_id)
    if not form_instances:
        return ApiResponse.fail(message="未找到该报告数据.")
    form_data = form_instances[0].form_data
    report_type = form_data.get("selectField_lp9egpd9")
    area = form_data.get("cascadeSelectField_lpgahbwq_id")
    datasource["工程名称"] = form_data.get("textField_lphpacz0")
    datasource["委托单位"] = form_data.get("textField_lphpacz4")
    datasource["报告名称"] = form_data.get("selectField_lpb4vtbt")
    datasource["设计单位"] = form_data.get("textField_lpgut0nt")
    datasource["勘察单位"] = form_data.get("textField_lpgut0nr")
    datasource["施工单位"] = form_data.get("textField_lpgut0nq")
    datasource["监理单位"] = form_data.get("textField_lpgut0ns")
    datasource["工程地址"] = form_data.get("textField_lphrnneu")
    datasource["评估类别"] = form_data.get("selectField_lp93kxv5")
    datasource["检测类别"] = form_data.get("selectField_lp93kxv5")
    datasource["样品名称"] = form_data.get("textField_lr0cupsi")
    datasource["工程类别"] = form_data.get("selectField_lp93kxv5")
    datasource["检测项目"] = form_data.get("selectField_lp93kxv5")
    datasource["监管编号"] = form_data.get("textField_lpb5xuuu")
    datasource["报告标题"] = form_data.get("textField_lv25b13o")
    datasource["司法编号"] = form_data.get("textField_lpb5xuup")
    
    if form_data.get("textField_ltmlzgdv"):
        sign_info = form_data.get("textField_ltmlzgdv")
        try:
            data_dict = json.loads(sign_info)  # 假设输入总是合法的JSON格式
            
            # 检查是否包含键 'report_code'
            if 'report_code' in data_dict:
                print("报告代码:", data_dict['report_code'])
                datasource["报告编号"] = data_dict['report_code']
            else:
                # 如果不包含所需的键，则设置datasource中的默认值
                datasource["报告编号"] = form_data.get("textField_lp93kxup")
        except:
            datasource["报告编号"] = form_data.get("textField_lp93kxup")    
    else:
        # 如果字符串为空，也设置datasource中的默认值
        datasource["报告编号"] = form_data.get("textField_lp93kxup")    
        
        
    report_code = form_data.get("textField_lp93kxup")
    datasource["二维码"] =  {
                     "type":"qrcode",
                     "width":30,
                     "text":report_code
                 }
    
    if form_data.get("dateField_lp93kxx6"):
        datasource["检测日期"] = {
                    "type": "date",
                    "value": form_data.get("dateField_lp93kxx6"),
                    "format":"%Y年%m月%d日"
                }
    if form_data.get("dateField_lpgnxeft"):
        datasource["分隔符"] = "-"
        datasource["检测日期至"] = {
                    "type": "date",
                    "value": form_data.get("dateField_lpgnxeft"),
                    "format":"%Y年%m月%d日"
                }
    if form_data.get("dateField_lpb39cyx"):
        datasource["签发日期"] = {
                    "type": "date",
                    "value": form_data.get("dateField_lpb39cyx"),
                    "format":"%Y年%m月%d日"
                }
    jcr1_id = get_user_id_in_form_data(form_data,"selectField_lpgut0ng")
    print('jcr1_id',jcr1_id)
    if jcr1_id:
        jcr1, _ = get_user_by_yida_user_id(
            jcr1_id, report_code)
        datasource["检测人1"] = jcr1['name']
        datasource["检测人签名1"] = jcr1.get("sign_arr")

    jcr2_value = form_data.get("selectField_lqeidrd3")
    if jcr2_value:
        if("-" in jcr2_value):
            jcr2_id = jcr2_value.split("-")[1]
        else:
            jcr2_id = jcr2_value
        if (jcr2_id):
            jcr2, _ = get_user_by_yida_user_id(
                jcr2_id, report_code)
            datasource["检测人2"] = jcr2['name']
            datasource["检测人签名2"] = jcr2.get("sign_arr")
    
    jcr3_value = form_data.get("selectField_mbhlc9nn")
    if jcr3_value:
        if("-" in jcr3_value):
            jcr3_id = jcr3_value.split("-")[1]
        else:
            jcr3_id = jcr3_value
        if (jcr3_id):
            jcr3, _ = get_user_by_yida_user_id(
                jcr3_id, report_code)
            datasource["检测人3"] = jcr3['name']
            datasource["检测人签名3"] = jcr3.get("sign_arr")
        
    app_history = yida_client.get_approve_history(form_inst_id,admin_user_id)
    shr_node = next((item for item in reversed(app_history) if item.show_name == "待审核"), None)
    if shr_node:
        shr, sign_method = get_user_by_yida_user_id(
            shr_node.operator_user_id, report_code)
        if (sign_method == "钉钉签名"):
            if "digitalSignatureField_lqrz4eha" in form_data:
                datasource["审核人签名"] = form_data["digitalSignatureField_lqrz4eha"]
        datasource["审核人"] = shr['name']
    pzr_node = next((item for item in reversed(app_history) if item.show_name == "总工审核"), None)

    if pzr_node:
        pzr, sign_method = get_user_by_yida_user_id(
            pzr_node.operator_user_id, report_code)
        if (sign_method == "钉钉签名"):
            if "digitalSignatureField_lqdi3j6t" in form_data:
                datasource["批准人签名"] = form_data["digitalSignatureField_lqdi3j6t"]
        datasource["批准人"] = pzr['name']

    group_leader_id = get_user_id_in_form_data(form_data,"selectField_lqvpbi42")
    if (group_leader_id):
        group_leader, _ = get_user_by_yida_user_id(
            group_leader_id, report_code)
        datasource["组长"] = group_leader['name']
        datasource["组长签名"] = group_leader['sign_arr']
        datasource["从事专业_组长"] = group_leader.get("subject","")
        datasource["技术职称_组长"] = group_leader.get("job_title","")

    group_user1_id = get_user_id_in_form_data(form_data,"selectField_lqvpbi43")
    if (group_user1_id):
        group_user1, _ = get_user_by_yida_user_id(
            group_user1_id, report_code)
        datasource["组员一"] = group_user1['name']
        datasource["组员一签名"] = group_user1.get("sign_arr")
        datasource["从事专业_组员一"] = group_user1.get("subject","")
        datasource["技术职称_组员一"] = group_user1.get("job_title","")

    group_user2_id = get_user_id_in_form_data(form_data,"selectField_lqvpbi45")
    if (group_user2_id):
        group_user2, _ = get_user_by_yida_user_id(
            group_user2_id, report_code)
        datasource["组员二"] = group_user2['name']
        datasource["组员二签名"] = group_user2.get("sign_arr")
        datasource["从事专业_组员二"] = group_user2.get("subject","")
        datasource["技术职称_组员二"] = group_user2.get("job_title","")
    celery_result = generateReportPdf.delay(uuid_string, form_data,datasource,report_code,report_type,form_inst_id)
    logger.info(f"celery_result:{celery_result.id}")
    logger.info(f"报告生成中...")
    return ApiResponse.success(message=f"报告{report_code}数据已导入,正在生成报告，请稍后")

# 根据user_id获取人员信息
def get_user_by_yida_user_id(user_id: str, report_code):
    user_form_uuid = "FORM-861F9E6F4AAE4D73A255247BF7991765XAKG"
    userinfo = yida_client.get_form_data_by_search_field(form_uuid=user_form_uuid, userId=admin_user_id, search_field=[
      {
        "type": "TEXT",
        "operator": "eq",
        "componentName": "TextField",
        "key": "textField_lp0zbal4",
        "value": user_id
      }
    ])
    user = {}
    if (userinfo):
        userinfo = userinfo[0].form_data
        user["name"] = userinfo["textField_lp0tv654"]
        user["subject"] = userinfo.get("textField_lqvoc0pq","")
        user["job_title"] = userinfo.get("textField_lqvoc0pr","")
        if "radioField_lqdk47dg" in userinfo:
            if (userinfo["radioField_lqdk47dg"] == "电子签名"):
                if "digitalSignatureField_lp0tv65b" in userinfo:
                    user["sign_arr"] = userinfo["digitalSignatureField_lp0tv65b"]
            elif (userinfo["radioField_lqdk47dg"] == "钉钉签名"):
                # 获取该流程下用户的签名
                qm_form_uuid = "FORM-36CB6E26E47043A4ADAE0C923F7E730DEW85"
                qminfo = yida_client.get_form_data_by_search_field(form_uuid=qm_form_uuid, userId=admin_user_id, search_field={
                    "textField_lqvmzy2z": report_code,
                    "textField_lqvmzy30": user_id
                })
                if (qminfo):
                    qminfo = qminfo[0].form_data
                    if "digitalSignatureField_lqvmzy35" in qminfo:
                        user["sign_arr"] = qminfo["digitalSignatureField_lqvmzy35"]
            return user, userinfo["radioField_lqdk47dg"]
        else:
            return None, None
        

def get_user_id_in_form_data(form_data,component_id,is_id=False):
    '''从表单中获取正确的user_id'''
    pattern = r'^[a-zA-Z0-9-]+$'
    user_value = form_data.get(component_id)
    print('user_value',user_value)
    if not user_value:
        return None
    if bool(re.match(pattern, user_value)):
        return user_value
    if "-" in user_value:
        user_value = user_value.split("-")[-1]
        if bool(re.match(pattern, user_value)):
            return user_value
    if not is_id:
        return get_user_id_in_form_data(form_data,component_id+"_id",True)
    return None





@csrf_exempt
@require_http_methods(["POST"])
def foundation_install_statistics(request):
    '''基坑打印'''
    reqData = json.loads(request.body)
    model_id = 200
    form_uuid = "FORM-A103E5D737D74894AADA078ED12680FAYX6N"
    install_man = reqData.get("textField_lusmqf7r") or reqData.get("textField_lusmqf7s")
    result,total = yida_client.get_all_form_data_by_search_field(form_uuid,admin_user_id,reqData)
    search_date_range = reqData.get("dateField_lusmqf7o") or ["",""]
    if reqData.get("textField_lusmqf7r"):
        install_man_type = "主安装人"
        install_cost_key = "numberField_m1h95yt2"
    else:
        install_man_type = "副安装人"
        install_cost_key = "numberField_m1h95yt3"
    render_data = {
        "统计开始日期":date_format(search_date_range[0]),
        "统计结束日期":date_format(search_date_range[1]),
        "条件":",".join([str(value) for key, value in reqData.items() if key != "dateField_lusmqf7o" and value]),
        "安装人类别":install_man_type,
        "产品安装信息":[{
            **item.form_data,
            "安装人":install_man,
            "安装费": item.form_data.get(install_cost_key),
        } for item in result]
    }
    res = xm_client.render_model_xlsx(model_id,render_data)
    if(res.get("code")==200):
        return ApiResponse.success(data=res.get("data"))
    else:
        return ApiResponse.fail(message=res.get("message"))


@csrf_exempt
@require_http_methods(["GET"])
def foundation_preuse_sign(request):
    form_inst_id = request.GET.get("form_inst_id") # FINST-54A66HC1YT9O2IMN8VZM79DIGVG23CIGQ8M0MQ41
    form_uuid = "FORM-B03AFB7805D24FD9B5502EFC344AB5CFL4W1"
    result = yida_client.get_form_items_by_ids(form_uuid,form_inst_id,admin_user_id)
    if result:
        form_data = result[0].form_data
    else:
        return ApiResponse.fail(message="未找到该表单实例")
    table_data = form_data.get("tableField_m0kodbt8")
    pre_form_uuid = "FORM-EF4A47F1EEC549C4B2B8DC428F42C3475OBQ"
    for item in table_data:
        try:
            product = json.loads(json.loads(item.get("associationFormField_lz85phco_id")))
            res = yida_client.create_form_data(pre_form_uuid,admin_user_id,{
                "associationFormField_lz85jluh":[
                  {
                    "appType": 'APP_R3U6VT51DXVY8NTP4I0Z', 
                    "formType": 'receipt',
                    "formUuid": form_uuid,
                    "instanceId": form_inst_id,
                    "title": form_data.get("textField_lz95zyrg"),
                  },  
                ],# 项目名称
                "associationFormField_lz85phco":product,# 产品
                "textField_lzm251hb":product[0].get("title") if product else "",
                "numberField_lz85jlui":item.get("numberField_m0kodbt9"),
                "numberField_lz85jluj":item.get("numberField_m0kodbtb"),
                "numberField_lz85jlum":item.get("numberField_m0kodbta"),
                "textField_lz85phcm":form_data.get("textField_lz95zyrg"),
                "textField_lzm251h8":item.get("textField_m0kodbtc"),
                "textField_lzm251h7":item.get("textField_lzm251h7"),
                "numberField_lzm251ha":item.get("numberField_m0kodbtd"),
                "selectField_lzmcok0q":item.get("selectField_m0kodbte"),
                "textField_lzqey43d":form_data.get("selectField_m0kodbtg"),
            })
        except Exception as err:
            continue
    return ApiResponse.success("同步成功")


@csrf_exempt
@require_http_methods(["GET"])
def auto_approve(request):
    form_inst_id = request.GET.get("form_inst_id")
    report_type = request.GET.get("report_type")
    area = request.GET.get("area")
    salsman = request.GET.get("salsman")
    threading.Thread(target=auto_approve_thread, args=(form_inst_id,report_type,salsman,area,)).start()
    return ApiResponse.success("自动受理任务已受理")

@csrf_exempt
@require_http_methods(["POST"])
def batch_process_agree(request):
    params = json.loads(request.body)
    remark = params.get("remark")
    userId = params.get("userId")
    taskInformationList = params.get("taskInformationList")
    try:
        yida_client.batch_process_agree(remark,userId,taskInformationList,"agree")
    except Exception as err:
        return ApiResponse.success("审批异常")
    return ApiResponse.success("批量同意已完成")


def auto_approve_thread(form_inst_id,report_type,salsman,area):
    '''李素娇跳过审核'''
    time.sleep(10) # 延时等待宜搭进行到目标节点
    app_history = yida_client.get_approve_history(form_inst_id,admin_user_id)
    target_node = next((item for item in reversed(app_history) if (item.show_name == "待审核" and item.action_exit == "doing")), None)
    if(target_node):
        result = yida_client.get_form_data_by_search_field(report_type_form_uuid,
                                                  yida_client.admin_user_id,
                                                  [
                                                    {
                                                      "type": "TEXT",
                                                      "operator": "eq",
                                                      "componentName": "TextField",
                                                      "key": "textField_lpmab75n",
                                                      "value": report_type
                                                    }
                                                  ])
        form_data = result[0].form_data
        no_approve_salesman:str = form_data.get("textareaField_m3y31gn3") # 需要审核的业务员
        no_approve_area = form_data.get("tableField_m3y7zump") # 需要审核的地区
        no_approve_area_arr = ["_".join(item.get("cascadeSelectField_lpgahbwq_id")) for item in no_approve_area]
        if no_approve_salesman:
            no_approve_salesman_arr = no_approve_salesman.split("\n")
            if no_approve_salesman_arr and salsman in no_approve_salesman_arr:
                return
        if no_approve_area_arr and area in no_approve_area_arr:
            return
        # yida_client.execute_task(form_inst_id,target_node.task_id,target_node.operator_user_id)
        yida_client.execute_task(form_inst_id,target_node.task_id,"4302516026430609")

import oss2

@csrf_exempt
@require_http_methods(["GET"])
def archive_to_xujf_com(self):
    with open('yida_app_service/chengxiang/resorce/bak_list.txt', 'r') as file:
        records = file.readlines()

    # 去掉每行末尾的换行符，并返回一个列表
    records = [line.strip() for line in records]
    auth = oss2.Auth("LTAI5t6uQ1q8XbgYHwVBG7k9", "Q0bBMa76xxGEE2pC6US6ifYDUc5tX7")
    cname = 'https://doc.zjxmyq.cn'
    xm_bucket = oss2.Bucket(auth, cname, 'xiaming-report',
                        is_cname=True, connect_timeout=30)
    for index,record in enumerate(records):
        try:
            record_arr = record.split("	")
            report_id = record_arr[0]
            path = record_arr[1]
            logger.info(f"正在迁移第{index + 1}份报告: {record}")
            objects = xm_bucket.list_objects(prefix=path)
            for obj in objects.object_list:
                obj_key = obj.key
                download_url = xm_bucket.sign_url('GET', obj_key, 3600)
                with requests.get(download_url) as response:
                    logger.info("正在迁移...")
                    cover_content = response.content
                    bucket.put_object(obj_key, cover_content)
            logger.info("迁移完成")
            report = Report.objects.get(id=report_id)
            report.save()
        except Exception as err:
            logger.error(err)
    return ApiResponse.success("success")

@csrf_exempt
@require_http_methods(["GET"])
def transfer_to_xu_com(request):
    '''文件迁移'''
    report_codes = [
            "CXLL-DH-2400006",
            "CXLL-SS-2400009",
            "CXLL-SS-2400004",
            "CXJL-WL-2400029",
            "CXJL-WL-2400026",
            "CXLL-SS-2400010",
            "CXLL-SS-2400013",
            "CXJL-WL-2400032",
            "CXJL-LH-2400022",
            "CXJL-WL-2400027",
            "CXJL-WL-2400038",
            "CXJL-WL-2400031",
            "CXJL-WL-2400043",
            "CXJL-WL-2400036",
            "CXJL-WL-2400037",
            "CXLL-SS-2400005",
            "CXLL-SS-2400008",
            "CXLL-SS-2400012",
            "CXJL-WL-2400025",
            "CXLL-SS-2400011",
            "CXJL-WL-2400035",
            "CXJL-WL-2400028",
            "CXJL-WL-2400030",
            "CXJL-WL-2400040",
            "CXJL-WL-2400033",
            "CXJL-WL-2400039",
            "CXJL-JJ-2400042",
            "CXJL-WL-2400041",
            "CXJL-WL-2400042",
            "CXLL-SS-2400002",
            "CXLO-PT-2300049",
            "CXJL-LH-2400021",
            "CXJL-DH-2400006",
            "CXKO-QT-2300001",
            "CXLO-PT-2300048",
            "CXJL-LH-2400020",
            "CXLL-DH-2400005",
            "CXJN-XJ-2400019",
            "CXJN-XJ-2400021",
            "CXJN-XJ-2400023",
            "CXJN-XJ-2400025",
            "CXJN-XJ-2400027",
            "CXJN-XJ-2400029",
            "CXJN-XJ-2400031",
            "CXJN-XJ-2400033",
            "CXJN-XJ-2400035",
            "CXJN-XJ-2400037",
            "CXJN-XJ-2400039",
            "CXJL-XJ-2400245",
            "CXJL-XJ-2400244",
            "CXJL-XJ-2400243",
            "CXJL-XJ-2400242",
            "CXJN-XJ-2400017",
            "CXJN-XJ-2400020",
            "CXJN-XJ-2400022",
            "CXJN-XJ-2400024",
            "CXJN-XJ-2400026",
            "CXJN-XJ-2400028",
            "CXJN-XJ-2400030",
            "CXJN-XJ-2400032",
            "CXJN-XJ-2400034",
            "CXJN-XJ-2400036",
            "CXJN-XJ-2400038",
            "CXJL-XJ-2400317",
            "CXJL-XJ-2400318",
            "CXLL-DS-2400135",
            "CXLL-DS-2400134",
            "CXJL-HY-2400130",
        ]
    for report_code in report_codes:
        result = yida_client.get_form_data_by_search_field(report_form_uuid,
                                                            admin_user_id,
                                                            [
                                                                {
                                                                    "type": "TEXT",
                                                                    "operator": "eq",
                                                                    "componentName": "TextField",
                                                                    "key": "textField_lp93kxup",
                                                                    "value": report_code
                                                                }
                                                            ]
                                                          )
        if result:
            start_backup_task_test(result[0],report_form_uuid)
        else:
            print(f"{report_code}未找到对应数据")

@csrf_exempt
@require_http_methods(["POST"])
def batch_gen_report(request):
        req_data = json.loads(request.body)
        report_code_list = req_data.get("report_code_list")
        for report_code in report_code_list:
            regen = False
            try:
                report = Report.objects.get(report_code=report_code)
                if not report.digital_sign_order_no:
                    regen = True
            except Report.DoesNotExist:
                regen = True
            if regen:
                print(f"开始生成报告{report_code}")
                result = yida_client.get_form_data_by_search_field(report_form_uuid,admin_user_id,
                                                    [
                                                        {
                                                            "type": "TEXT",
                                                            "operator": "eq",
                                                            "componentName": "TextField",
                                                            "key": "textField_lp93kxup",
                                                            "value": report_code
                                                        }
                                                    ])
                if not result:
                    continue
                model_uuid = result[0].form_data.get("textField_lqbsdaaj")
                form_inst_id = result[0].form_instance_id
                headers = {
                        'Content-Type': 'application/json'
                    }
                response = requests.post(f"http://localhost:8000/api/v1/yida-app/chengxiang/gen_base/{model_uuid}",
                              json={
                                  "formInstId": form_inst_id
                              },
                              headers=headers)
                if response.status_code == 200:
                    print("success")
                    with open("yida_app_service/chengxiang/test_log.txt", "a", encoding="utf-8") as file:
                        file.write(f"{report_code}\n")
                    time.sleep(3)
                else:
                    print("error")
                    with open("yida_app_service/chengxiang/test_err.txt", "a", encoding="utf-8") as file:
                        file.write(f"{report_code}\n")
                    time.sleep(3)
        return ApiResponse.success("生成报告任务已完成")


@csrf_exempt
@require_http_methods(["POST"])
def update_report_attachment(request):
    req_data = json.loads(request.body)
    report_codes = req_data.get("report_codes")
    for report_code in report_codes:
        print("开始更新报告附件",report_code)
        try:
            report = Report.objects.get(report_code=report_code)
        except Report.DoesNotExist:
            result = yida_client.update_form_data_by_field("FORM-0BC04FECE4F544B297D37901915570D2OEIY",
                                                    admin_user_id,
                                                    search_field=[
                                                        {
                                                            "type": "TEXT",
                                                            "operator": "eq",
                                                            "componentName": "TextField",
                                                            "key": "textField_lp93kxup",
                                                            "value": report_code
                                                        }
                                                    ],
                                                    update_field={
                                                        "attachmentField_lqrz4ehj":[]
                                                    })
            print("报告不存在",result)
            continue
        report_path = report.report_path
        if not report_path:
            continue
        res = bucket.list_objects(prefix=f"{report_path}/attachmentField_lqrz4ehj/")
        if not res.object_list:
            with open("yida_app_service/chengxiang/test_err.txt", "a", encoding="utf-8") as file:
                        file.write(f"{report_path}\n")
            continue
        path = res.object_list[-1].key
        full_path = f"https://api.zjcxjc.cn/api/v1/yida-app/common/download_file/{path}"
        result = yida_client.update_form_data_by_field("FORM-0BC04FECE4F544B297D37901915570D2OEIY",
                                                    admin_user_id,
                                                    search_field=[
                                                        {
                                                            "type": "TEXT",
                                                            "operator": "eq",
                                                            "componentName": "TextField",
                                                            "key": "textField_lp93kxup",
                                                            "value": report_code
                                                        }
                                                    ],
                                                    update_field={
                                                        "attachmentField_lqrz4ehj":[
                                                                                        {
                                                                                        "downloadUrl": full_path,
                                                                                        "name": f"{report_code}.pdf",
                                                                                        "previewUrl": full_path,
                                                                                        "url": full_path,
                                                                                        "ext": "pdf"
                                                                                        }
                                                                                    ]
                                                    })
        print(result)

def get_report_detail(request):
    report_code = request.GET.get("report_code")
    form_uuid = "FORM-0BC04FECE4F544B297D37901915570D2OEIY"
    res_data = yida_client.get_form_data_by_search_field(form_uuid,
                                                        admin_user_id,
                                                        [
                                                          {
                                                            "type": "TEXT",
                                                            "operator": "eq",
                                                            "componentName": "TextField",
                                                            "key": "textField_lp93kxup",
                                                            "value": report_code
                                                          }
                                                        ])
    if not res_data:
        form_uuid = "FORM-5E859C69D49F452694E420EF7A162B4371MF"
        res_data = yida_client.get_form_data_by_search_field(form_uuid,
                                                            admin_user_id,
                                                            [
                                                              {
                                                                "type": "TEXT",
                                                                "operator": "eq",
                                                                "componentName": "TextField",
                                                                "key": "textField_lp93kxup",
                                                                "value": report_code
                                                              }
                                                            ])
    form_data = res_data[0].form_data
    detection_date = datetime.fromtimestamp(form_data["dateField_lp93kxx6"]/1000).strftime("%Y-%m-%d")
    if form_data.get("dateField_lpgnxeft"):
        detection_date = detection_date + " - " +datetime.fromtimestamp(form_data["dateField_lpgnxeft"]/1000).strftime("%Y-%m-%d")
    report_info = {
      "project_name":form_data.get('textField_lphpacz0'),
      "customer_name":form_data.get("textField_lphpacz4"),
      "address":form_data.get("textField_lphrnneu"),
      "report_type":form_data.get("selectField_lqx655zl") or form_data.get("selectField_m5fq21fd"),
      "detection_date":detection_date,
    }
    return ApiResponse.success(report_info)